package com.relax.netty.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;

public class NioTest12_server {
    private static Set<SocketChannel> socketChannelHashSet = new HashSet<>();

    public static void main(String[] args) throws IOException {
        /**
         * 服务端四部
         */
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        Selector selectorConnector = Selector.open();
        Selector selectorRead = Selector.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.bind(new InetSocketAddress(6666));
        serverSocketChannel.register(selectorConnector, SelectionKey.OP_ACCEPT);

        /**
         * 主从reactor, 主reactor只处理连接请求,从reactor处理读请求
         */
        new Thread(()->{
            try {
                handlerConnector(selectorConnector,selectorRead);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();



        new Thread(()->{
            try {
                handlerRead(selectorConnector);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();


    }

    private static void handlerRead(Selector selectorRead) throws IOException {
        /**
         * 服务区死循环,执行对应的事件
         */
        while (true) {
            //1.阻塞等待事件
            final int number = selectorRead.select();
            System.out.println("handlerRead selector.select() 有数据"+number+"时间:"+ LocalDateTime.now());
            //2.获得所有的SelectionKey
            final Set<SelectionKey> selectionKeys = selectorRead.selectedKeys();
            selectionKeys.forEach(selectionKey -> {
                SocketChannel socketChannel;
                try {
                  if (selectionKey.isReadable()) {
                        System.out.println("handlerRead 可读事件,时间"+ LocalDateTime.now());
                        //3-2.处理clinet发送的消息
                        Charset charset = Charset.forName("utf-8");
                        socketChannel = (SocketChannel) selectionKey.channel();
                        final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                        final int read = socketChannel.read(byteBuffer);
                        if (read > 0) {
                            byteBuffer.flip();
                            String msg = String.valueOf(charset.decode(byteBuffer).array());
                            System.out.println(socketChannel + ",客户端发送的数据为:" + msg);
                            //将客户端发送数据广播出去
                            for (SocketChannel clientChannel : socketChannelHashSet) {
                                final ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
                                byteBuffer1.put(("客户端发送的数据为:" + msg).getBytes());
                                byteBuffer1.flip();
                                clientChannel.write(byteBuffer1);
                            }
                        }

                    }else {
                      System.out.println("handlerRead xxxxxxxxxxxxxxxxxxxxx,时间"+ LocalDateTime.now());
                  }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            //清空
            selectionKeys.clear();
        }
    }

    private static void handlerConnector( Selector selector, Selector selectorRead) throws IOException {
        /**
         * 服务区死循环,执行对应的事件
         */
        while (true) {
            //1.阻塞等待事件
            final int number = selector.select();
            System.out.println("handlerConnector  selector.select() 有数据"+number+"时间:"+ LocalDateTime.now());
            //2.获得所有的SelectionKey
            final Set<SelectionKey> selectionKeys = selector.selectedKeys();
            selectionKeys.forEach(selectionKey -> {
                SocketChannel socketChannel;
                try {
                    //3-1.如果是连接事件,把client的socket放在set中用于后面的数据分发
                    if (selectionKey.isAcceptable()) {
                        System.out.println("handlerConnector 连接事件,时间"+ LocalDateTime.now());
                        final ServerSocketChannel serverSocketChannel1 = (ServerSocketChannel) selectionKey.channel();
                        //获取client的socketchannel--并注册到selector
                        socketChannel = serverSocketChannel1.accept();
                        socketChannel.configureBlocking(false);
                        socketChannel.register(selectorRead, SelectionKey.OP_READ);
                        socketChannelHashSet.add(socketChannel);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            //清空
            selectionKeys.clear();
        }
    }
}
